package wallet

import (
	"context"
	"fmt"
	"sync"

	"jgt-sdk/asapi"
	"jgt-sdk/utils"
)

var (
	internalHandle *Handle
	once           sync.Once
)

// InitWallet 初始化支付服务
func InitWallet(as *asapi.APIHandle) *Handle {
	once.Do(func() {
		internalHandle = &Handle{
			as:       as,
			identify: "WALLET",
			lock:     new(sync.RWMutex),
		}
	})
	return internalHandle
}

// GetHandle 获取支付服务
func GetHandle() *Handle {
	return internalHandle
}

// Handle 支付服务
type Handle struct {
	as       *asapi.APIHandle
	identify string
	host     string
	lock     *sync.RWMutex
	traceID  string
}

func (a *Handle) getHost() string {
	a.lock.RLock()
	host := a.host
	a.lock.RUnlock()
	if host == "" {
		a.lock.Lock()
		defer a.lock.Unlock()
		v, err := a.as.GetServiceHost(a.identify)
		if err == nil && v != "" {
			host = v
			a.host = v
		}
	}
	return host
}

func (a *Handle) getContext() context.Context {
	return utils.NewTraceIDContext(context.Background(), a.traceID)
}

// GetURL 获取URL
func (a *Handle) GetURL(router string) (string, error) {
	host := a.getHost()
	if host == "" {
		return "", fmt.Errorf("无效的Host")
	}
	return utils.RequestURL(host, router), nil
}

type PayType string

const (
	AlipayApp PayType = "alipay_app"
	WechatApp         = "weichat_app"
)

const (
	Success  string = "success"
	Fail            = "fail"
	Error           = "error"
	NotFound        = "not_found"
)

type client interface {
	pay(h *Handle, params *PayParams) (map[string]string, error)
	check(h *Handle, params *CheckParams) (*CheckResult, error)
}

func newClient(paytype PayType) client {
	var c client
	switch paytype {
	case AlipayApp:
		c = new(aliapp)
	case WechatApp:
		c = new(wechatapp)
	default:
		return nil
	}
	return c
}

type PayParams struct {
	Client   string
	OrderId  string
	Describe string
	Price    int64
	Tag      string
}

type CheckParams struct {
	Client  string
	Data    string
	OrderId string
}

type CheckResult struct {
	Result  string
	Msg     string
	Detail  string
	OrderID string
	BillID  string
	Price   int64
}

type QueryParams struct {
}

type QueryResult struct {
	Result    string `json:"result"`
	RecordID  string `json:"record_id"`
	OrderID   string `json:"order_id"`
	TradeID   string `json:"trade_id"`
	Price     int64  `json:"price"`
	RealPrice int64  `json:"real_price"`
	PayType   string `json:"pay_type"`
}

// Pay支付
func (a *Handle) Pay(paytype PayType, params *PayParams) (map[string]string, error) {
	c := newClient(paytype)
	if c == nil {
		return nil, fmt.Errorf("不支持此支付方式")
	}
	return c.pay(a, params)
}

// 同步回调检验
func (a *Handle) Check(paytype PayType, params *CheckParams) (*CheckResult, error) {
	c := newClient(paytype)
	if c == nil {
		return nil, fmt.Errorf("不支持此支付方式")
	}
	return c.check(a, params)
}

// 结果检查
func (a *Handle) Query(orderId string) (*QueryResult, error) {
	uslStr, err := a.GetURL(fmt.Sprintf("/srv/v1/order/%s", orderId))
	if err != nil {
		return nil, err
	}

	var result = new(QueryResult)

	err = utils.GetWithToken(a.getContext(), uslStr, a.as.GetTokenHandle().Get, nil, &result)

	return result, err
}

// 取消订单
func (a *Handle) Cancel(orderId string) error {
	uslStr, err := a.GetURL(fmt.Sprintf("/srv/v1/order/%s", orderId))
	if err != nil {
		return err
	}

	err = utils.DeleteWithToken(a.getContext(), uslStr, a.as.GetTokenHandle().Get, nil)

	return err
}
